﻿using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ewk.MachineLearning.Genetic.Programming.Program.Functions;

namespace Ewk.MachineLearning.Genetic.Programming.Program
{
    /// <summary>
    /// The function node is a function in the program.
    /// </summary>
    internal class FunctionNode : Node
    {
        private Function _function;

        /// <summary>
        /// Initializes a new instance.
        /// </summary>
        /// <param name="function">The function that will be called when the value of this node is asked.
        /// The function will recieve the values of the childnodes of this instance as parameter.</param>
        public FunctionNode(Function function)
        {
            _function = function;
            ChildNodes = new List<Node>();
        }

        /// <summary>
        /// Mutates this <see cref="FunctionNode"/>.
        /// </summary>
        public void Mutate(FunctionSet functionSet)
        {
            _function = functionSet.GetRandom(_function.Arity);
        }

        /// <summary>
        /// The childnodes of this instance. The values of the childnodes are the arguments of the function.
        /// </summary>
        public IEnumerable<Node> ChildNodes { get; set; }

        /// <summary>
        /// Gets the <see cref="IFunctionDefinition"/> for this node.
        /// </summary>
        public IFunctionDefinition FunctionDefinition
        {
            get { return _function; }
        }

        public override dynamic GetValue()
        {
            return _function.Value
                (
                    ChildNodes.Select(node =>
                                      node.GetValue())
                );
        }

        public override Node Clone()
        {
            return new FunctionNode(_function)
                {
                    ChildNodes = ChildNodes.Select(child =>
                                                   child.Clone())
                };
        }

        public override string ToString()
        {
            var sb = new StringBuilder();

            sb.Append("(");
            sb.Append(_function.ToString());

            foreach(var childNode in ChildNodes)
            {
                sb.Append(" " + childNode.ToString());
            }

            sb.Append(")");

            return sb.ToString();
        }
    }
}